#include "uniformparameterwidget.h"


const char *UniformParameterWidget::fCgProgramName = "03_uniform_parameter";
const char *UniformParameterWidget::fCgVertexProgramFileName = "C3E1v_anycolor.cg";
const char *UniformParameterWidget::fCgVertexProgramName = "C3E1v_anycolor";
const char *UniformParameterWidget::fCgFragmentProgramFileName = "C3E1f_passthru.cg";
const char *UniformParameterWidget::fCgFragmentProgramName = "C3E1f_passthru";

void UniformParameterWidget::cgCheckForError(const char *situation)
{
	CGerror error;
	const char *str = cgGetLastErrorString(&error);
	if(error!= CG_NO_ERROR){
		QString info = QString("%1 %2 %3").arg(fCgProgramName).arg(situation).arg(str);
		QMessageBox::information(NULL,"cg error",info);
		exit(1);
	}
}

UniformParameterWidget::UniformParameterWidget(QWidget *parent)
	: QGLWidget(parent)
{
	
}

UniformParameterWidget::~UniformParameterWidget()
{
	cgDestroyProgram(fCgVertexProgram);
	cgDestroyProgram(fCgFragmentProgram);
	cgDestroyContext(fCgContext);
}

void UniformParameterWidget::initializeGL()
{
	glClearColor(0.1,0.1,0.5,1.0);
	initCG();
}

void UniformParameterWidget::resizeGL(int w, int h )
{
	if(h==0)
		h=1;
	glViewport(0,0,w,h);
}

void UniformParameterWidget::paintGL()
{
	glClear(GL_COLOR_BUFFER_BIT);
	
	//bind vertex program 
	cgGLBindProgram(fCgVertexProgram);
	cgCheckForError("binding vertex program");
	//enable vertex profile
	cgGLEnableProfile(fCgVertexProfile);
	cgCheckForError("enablding vertex profile");
	
	//binding fragment profile 
	cgGLBindProgram(fCgFragmentProgram);
	cgCheckForError("binding fragment program");
	//enable fragment profile
	cgGLEnableProfile(fCgFragmentProfile);
	cgCheckForError("enable fragment profile");
	
	drawModel();
	cgGLDisableProfile(fCgVertexProfile);
	cgCheckForError("disable vertex profile");
	cgGLDisableProfile(fCgFragmentProfile);
	cgCheckForError("disable fragment profile");

	glFlush();
}

void UniformParameterWidget::drawModel()
{	
	//set the uniform parameter into cg
	const float green[3] = {1.0,0.0,0.3};
	cgSetParameter3fv(fCgVertexParam_constantColor,green);
	glColor3f(1.0,0.0,1.0);
	//draw stars 
	drawStar(-0.1,0,5,0.5,0.2);
	drawStar(-0.84,0.1,5,0.3,0.12);
	drawStar(0.92,-0.5,5,0.25,0.11);
	
	glColor3f(0.0,0.0,1.0);
	cgSetParameter3f(fCgVertexParam_constantColor,0.0,1.0,0.1);
	drawStar(0.3,0.97,5,0.3,0.1);
	drawStar(0.94,0.3,5,0.5,0.2);
	drawStar(-0.97,-0.8,5,0.6,0.2);

}

void UniformParameterWidget::initCG()
{
	//creating context 
	fCgContext = cgCreateContext();
	cgCheckForError("creating context");
	cgGLSetDebugMode(CG_FALSE);
	cgSetParameterSettingMode(fCgContext,CG_DEFERRED_PARAMETER_SETTING);

	//selecting vertex profile 
	fCgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
	cgGLSetOptimalOptions(fCgVertexProfile);
	cgCheckForError("selecting vertex profile");

	//creating vertex program 
	fCgVertexProgram = cgCreateProgramFromFile(fCgContext,CG_SOURCE,fCgVertexProgramFileName,fCgVertexProfile,fCgVertexProgramName,NULL);
	cgCheckForError("creating vertex program from file");
	//loading vertex program
	cgGLLoadProgram(fCgVertexProgram);
	cgCheckForError("loading vertex program");
	
	//get uniform parameter 
	fCgVertexParam_constantColor = cgGetNamedParameter(fCgVertexProgram,"constantColor");
	cgCheckForError("could not get uniform parameter constantColor");

	//selecting fragment profile 
	fCgFragmentProfile =  cgGLGetLatestProfile(CG_GL_FRAGMENT);
	cgGLSetOptimalOptions(fCgFragmentProfile);
	cgCheckForError("selecting fragment profile");
	
	//creating fragment program from file
	fCgFragmentProgram = cgCreateProgramFromFile(fCgContext,CG_SOURCE,fCgFragmentProgramFileName,fCgFragmentProfile,fCgFragmentProgramName,NULL);
	cgCheckForError("creating fragment program from file");
	//loading fragment  program 
	cgGLLoadProgram(fCgFragmentProgram);
	cgCheckForError("loading fragment program ");


}

void UniformParameterWidget::drawStar(float x , float y , int starPoints , float R , float r)
{
	int i ;
	double piOverStarPoints = 3.14159 / starPoints ;
	double angle = 0.0;
	
	///update program parameter 
	cgUpdateProgramParameters(fCgVertexProgram);

	//draw model 
	glBegin(GL_TRIANGLE_FAN);
		glVertex2f(x,y);
		for(i=0;i<starPoints;++i){
			glVertex2f(x+R*cos(angle),y+R*sin(angle));
			angle += piOverStarPoints;
			glVertex2f(x+r*cos(angle),y+r*sin(angle));
			angle+= piOverStarPoints;
		}
		angle = 0;
		glVertex2f(x+R*cos(angle),y+R*sin(angle));
	glEnd();
}